#ifndef __POINT_LIGHTS_SAMPLER_HPP__
#define __POINT_LIGHTS_SAMPLER_HPP__

#include "TileNode.hpp"
#include "Mathematics/MVector2D.hpp"
#include <vector>


typedef std::vector<MVector2D> samplingPoints;


class PointLightsSampler
{
protected:
    PointLightsSampler(unsigned int iWidth = 0, unsigned int iHeight = 0);
	virtual ~PointLightsSampler();

	static unsigned int getFibonacciNumber(unsigned int iPosition);
	static unsigned int getRequiredSubdivLvl(unsigned int iImportance);
	static unsigned int getFCodeValue(unsigned int iBits, unsigned int iNumBits);

	static unsigned int getStructuralIdx(unsigned int iBits);
	static unsigned int getImportanceIdx(unsigned int iImportance);
	static MVector2D    getDisplacementVec(unsigned int iImportance, unsigned int iFCode, unsigned int iDirection);

	void         setSize(unsigned int iWidth, unsigned int iHeight);
	void         getSize(unsigned int* pWidth, unsigned int* pHeight);
	void         subdivideAll(int iIterations = 1);
	void         buildAdaptiveSubdivision(unsigned int iMinSubdivLvl = 6);

public:
	virtual unsigned int getImportanceAt(MVector2D point) = 0;	
	samplingPoints       getSamplingPoints();

private:

	class TileLeafIterator
	{
	public:
		TileLeafIterator() { m_pShape = NULL; }
		TileLeafIterator(TileNode* pNode) { begin(pNode); }

		void begin(TileNode* pNode)
		{
			TileNode* pTmp = pNode;

			while(!pTmp->isLeaf())
				pTmp = pTmp->getChild(0);

			m_pShape = pTmp;
		}

		void subdivide()
		{
			m_pShape->divide();
			m_pShape = m_pShape->getChild(0);
		}

		void destroySubTree()
		{
			if(m_pShape->getParent())
			{
				m_pShape = m_pShape->getParent();
				m_pShape->destroyBranch();
			}
		}

		bool next()
		{
			bool bSuccess = false;
			TileNode* pShape = m_pShape->getNextLeaf();

			if(pShape)
			{
				m_pShape = pShape;
				bSuccess = true;
			}
			else
			{
				m_pShape = pShape;
				bSuccess = false;
			}

			return bSuccess;
		}

		bool hasNext()
		{
			bool bSuccess = false;
			TileNode* pShape = m_pShape->getNextLeaf();

			if(pShape)
				bSuccess = true;

			return bSuccess;
		}

		TileNode* operator*()
		{
			return m_pShape;
		}

		TileNode* operator->()
		{
			return m_pShape;
		}

	private:
		TileNode* m_pShape;
	};

	unsigned int getImportanceAtAndInBounds(MVector2D point);
	bool         pointInBounds(MVector2D& point);
	void         gatherPoints(samplingPoints& points, bool bFilterBounds = true);

	TileNode*     m_pRootNode;
	unsigned int  m_iWidth;
	unsigned int  m_iHeight;
	
	static unsigned int  m_fibTable[64];
};

#endif //__POINT_LIGHTS_SAMPLER_HPP__

//EOF
